namespace EyeOpen.DddOrm.Data.Test
{
	using EyeOpen.DddOrm.Domain;
	using EyeOpen.DddOrm.Domain.Transactional;

	using NHibernate;

	using NHibernate.Cfg;

	using NHibernate.Dialect;

	using NHibernate.Mapping.ByCode;

	using NHibernate.Tool.hbm2ddl;

	public class NhibernateMediaUnitOfWorkDataSessionFactory
	{
		private readonly ISessionFactory sessionFactory;

		public NhibernateMediaUnitOfWorkDataSessionFactory()
		{
			var configuration = new Configuration();

			configuration.DataBaseIntegration(
				c =>
					{
						c.Dialect<MsSql2008Dialect>();
						c.ConnectionString = @"Data Source=.\SQLExpress;Initial Catalog=EyeOpen.DddOrm.Test;Integrated Security=True";
						c.KeywordsAutoImport = Hbm2DDLKeyWords.AutoQuote;
						c.SchemaAction = SchemaAutoAction.Create;
					});

			var mapper = new ModelMapper();

			mapper.Class<Category>(
				m =>
					{
						m.Id(x => x.Id, map => map.Generator(Generators.Assigned));
						m.Property(x => x.Name, p => p.NotNullable(true));
						m.ManyToOne(
							x => x.Parent,
							p =>
								{
									p.NotNullable(false);
									p.Column("ParentId");
								});
					});

			mapper.Class<Content>(
				m =>
					{
						m.Id(x => x.Id, map => map.Generator(Generators.Assigned));
						m.Property(x => x.Title, p => p.NotNullable(true));
						m.Property(x => x.Description, p => p.NotNullable(true));
						m.Bag<ContentCategory>(
							"contentCategoryList",
							p =>
								{
									p.Access(Accessor.Field);
									p.Cascade(Cascade.Merge);
								},
							r => r.OneToMany());
					});

			mapper.Class<ContentCategory>(
				m =>
					{
						m.Id(x => x.Id, map => map.Generator(Generators.Assigned));
						m.ManyToOne(x => x.Content, p => p.NotNullable(true));
						m.ManyToOne(x => x.Category, p => p.NotNullable(true));
					});

			mapper.Class<Portal>(
				m =>
					{
						m.Id(x => x.Id, map => map.Generator(Generators.Assigned));
						m.Property(x => x.Name, p => p.NotNullable(true));
						m.Bag(
							x => x.ContentList,
							p =>
								{
									p.Access(Accessor.Field);
									p.Cascade(Cascade.Merge);
								},
							r => r.OneToMany());
					});

			var mapping =
				mapper.CompileMappingFor(new[] { typeof(Category), typeof(Content), typeof(ContentCategory), typeof(Portal) });

			configuration.AddMapping(mapping);

			var xml = mapping.AsString();

			new SchemaExport(configuration).Execute(false, true, false);

			sessionFactory = configuration.BuildSessionFactory();
		}

		public IMediaUnitOfWork CreateUnitOfWork()
		{
			return MediaUnitOfWorkFactory.Create(new NhibernateDataSession(sessionFactory.OpenSession()));
		}
	}
}